package net.chrisrichardson.ec2deployer.cluster

import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.core.EC2
import net.chrisrichardson.ec2deployer.core.AWSProperties
import net.chrisrichardson.ec2deployer.core.EC2Server
import net.chrisrichardson.ec2deployer.applications.MySqlServer
import net.chrisrichardson.ec2deployer.applications.TomcatServer
import net.chrisrichardson.ec2deployer.applications.ApacheServer
import net.chrisrichardson.ec2deployer.core.EC2InstanceType

class ClusterInstanceTest extends GroovyTestCase {

    MockFor mockEc2
    ClusterSpec clusterSpec
    AWSProperties awsProperties

    MockFor mockDatabaseTier
    MockFor mockAppServerTier
    MockFor mockWebServerTier
    MockFor mockJmeterTier
    MockFor mockTopology
    MockFor mockClusterHosts
    MockFor mockTerracottaTier

    public void setUp() {
        mockEc2 = new MockFor(EC2.class)
        mockDatabaseTier = new MockFor(DatabaseTier)
        mockTerracottaTier = new MockFor(TerracottaTier)
        mockAppServerTier = new MockFor(AppServerTier)
        mockWebServerTier = new MockFor(WebServerTier)
        mockJmeterTier = new MockFor(JmeterTier)
        mockTopology = new MockFor(MultipleInstancesTopology)
        mockClusterHosts = new MockFor(ClusterHosts)

        clusterSpec = new ClusterSpec().tomcats(1).slaves(1).webApp('target/ptrack', "ptrack").catalinaOptsBuilder({builder, databasePrivateDnsName ->}).schema("ptrack", ["ptrack": "ptrack"])

        def props = new Properties()
        awsProperties = new AWSProperties(props)

    }

    public void testStart() {

        clusterSpec.topology(MultipleInstancesTopology.simpleName)
        clusterSpec.terracottaHosts(1)

        def hosts

        mockTopology.demand.newInstance {
            def topology = new MultipleInstancesTopology()
            topology
        }

        mockEc2.demand.startPolling {}
        mockTopology.demand.allocateServers {ec2, spec, reuse ->
            hosts = new ClusterHosts()
        }

        mockAppServerTier.demand.setWebServerTier{ webServerTier -> }

        mockDatabaseTier.demand.assignHosts {h -> assertEquals hosts, h}
        mockTerracottaTier.demand.assignHosts {h -> assertEquals hosts, h}
        mockAppServerTier.demand.assignHosts {h -> assertEquals hosts, h}
        mockWebServerTier.demand.assignHosts {h -> assertEquals hosts, h}
        mockJmeterTier.demand.assignHosts {h -> assertEquals hosts, h}

        mockAppServerTier.demand.uploadWebAppsToS3 {}

        // TODO - call servers
        mockDatabaseTier.demand.waitUntilRunning { }
        mockTerracottaTier.demand.waitUntilRunning { }
        mockAppServerTier.demand.waitUntilRunning { }
        mockWebServerTier.demand.waitUntilRunning { }
        mockJmeterTier.demand.waitUntilRunning { }

        mockDatabaseTier.demand.start {}
        mockTerracottaTier.demand.start {}
        mockAppServerTier.demand.start {}
        mockWebServerTier.demand.start {}
        mockJmeterTier.demand.start {}
        mockWebServerTier.demand.assignIpAddress{}

        mockClusterHosts.use {
            mockEc2.use {
                mockDatabaseTier.use {
                    mockTerracottaTier.use {
                        mockAppServerTier.use {
                            mockWebServerTier.use {
                                mockJmeterTier.use {
                                    mockTopology.use {
                                        def ec2 = new EC2(awsProperties)
                                        def clusterInstance = new ClusterInstance(ec2, clusterSpec, [:])
                                        clusterInstance.start(false)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

    }

    public void testRestoreServerState() {
        def serverState = [
                "tomcats": ["t1", "t2"],
                mySqlSlaves: ["slave1"],
                apacheServer: ["apache1"],
                "databaseServer": ["databaseServer2"],
                jmeter: ["jmeter1"]
        ]

        mockEc2.demand.pollStatus {}

        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}
        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}

        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}
        mockEc2.demand.getAwsProperties { awsProperties }

        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}
        mockEc2.demand.getAwsProperties { awsProperties }

        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}
        mockEc2.demand.findInstance {String instanceId -> println "finding $instanceId"; null}

        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            def clusterInstance = new ClusterInstance(ec2, clusterSpec, serverState)
            assertNotNull clusterInstance
            // TODO - not doing anything
        }

    }

    public void testAddAppServers() {

        mockAppServerTier.demand.setWebServerTier{ webServerTier -> }
        mockAppServerTier.demand.addAppServers {}
        mockWebServerTier.demand.start {}
        mockEc2.demand.startPolling {}
        
        mockEc2.use {
            mockAppServerTier.use {
                mockWebServerTier.use {
                    def ec2 = new EC2(awsProperties)
                    def clusterInstance = new ClusterInstance(ec2, clusterSpec)
                    clusterInstance.addAppServers 1
                }
            }
        }
   }

    public void testConfigureSecurityGroups() {
        clusterSpec.withSecurityGroupPrefix("test");
        mockEc2.demand.configureSecurityGroup {name, perms ->
            assertEquals("test-jmeter", name)
            assertEquals([:], perms)
        }
        mockEc2.demand.configureSecurityGroup {name, perms ->
            assertEquals("test-webServers", name)
            assertEquals(["${"test-jmeter"}" : [80] ], perms)
        }
        mockEc2.demand.configureSecurityGroup {name, perms ->
            assertEquals("test-dbslaves", name)
            assertEquals([:], perms)
        }
        mockEc2.demand.configureSecurityGroup {name, perms ->
            assertEquals("test-appServers", name)
            assertEquals([ "${"test-webServers"}" : [8009, 8010] ], perms)
        }
        mockEc2.demand.configureSecurityGroup {name, perms ->
            assertEquals("test-database", name)
            assertEquals(["${"test-dbslaves"}" : [3306], "${"test-appServers"}" : [3306] ], perms)
        }
        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            def clusterInstance = new ClusterInstance(ec2, clusterSpec)
            clusterInstance.configureSecurityGroups()

        }
    }
}